#pragma warning(disable : 4819)
#include "Game.h"
#include "GameScene.h"
#include "TextureLoader.h"
#include "Enemy.h"
#include "Player.h"
#include "Bullet.h"
#include "Animation.h"

GameScene::GameScene()
{
}

GameScene::~GameScene()
{
}

void GameScene::Init()
{
    generatePlayer();
    generateEnemy();
    generateEnemy();
    generateEnemy();
}

void GameScene::InitData(std::any data)
{
    terrainMap_ = std::any_cast<std::array<std::array<Terrain,MAP_HEIGHT>,MAP_WIDTH>>(data);
}

void GameScene::HandleEvent(SDL_Event *event)
{
}

UpDateResult GameScene::Update(float deltaTime)
{

    updateTanks(deltaTime);
    //更新子弹
    updateBullet(deltaTime);
    updateAniations(deltaTime);
    //更新玩家
    return updateResult_;
}

void GameScene::Render()
{
    SDL_RenderClear(Game::GetInstance().GetRenderer());
    // 渲染场景
    renderTerrain();
    //渲染坦克
    renderTanks();
    //渲染子弹
    renderBullet();

    renderAimetions();
    //渲染玩家
    SDL_RenderPresent(Game::GetInstance().GetRenderer());
}

void GameScene::updateBullet(float deltaTime)
{
    for(auto it = bullets_.begin();it!=bullets_.end();)
    {
        auto bullet = *it;
        bullet->Update(deltaTime);
        if(!bullet->isAlive_)
        {
            it = bullets_.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

void GameScene::updateTanks(float deltaTime)
{
    for(auto it = tanks_.begin();it!=tanks_.end();)
    {
        auto tank = *it;
        tank->Update(deltaTime);
        if(!tank->isAlive_)
        {
            if(!tank->isEnemy())
            {
                --life_;
                if(life_<0)
                {
                    //游戏结束
                    SDL_Log("Game Over");
                }
                else
                {
                    generatePlayer();
                }
            }
            else
            {
                enemyNum_--;
                if(enemyNum_<=0)
                {
                    //游戏胜利
                    SDL_Log("Game Win");
                }
                else
                {
                    generateEnemy();
                }
            }
            AddAnimation(std::make_shared<Explosion>(SDL_Point{static_cast<int>(tank->x_), static_cast<int>(tank->y_)}, 5));
            it = tanks_.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

void GameScene::updateAniations(float deltaTime)
{
    for(auto it = animations_.begin();it!=animations_.end();)
    {
        auto animation = *it;
        if(!animation->Update(deltaTime))
        {
            it = animations_.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

void GameScene::renderTerrain()
{
    for (int x = 0; x < MAP_WIDTH; x++)
    {
        for (int y = 0; y < MAP_HEIGHT; y++)
        {
            auto &terrain = terrainMap_[x][y];
            if (terrain.type == TerrainType::Empty)
            {
                continue;
            }
            auto texture = TextureLoader::Instance().GetTerrainTexture(terrain.type);
            if (terrain.type == TerrainType::Brick || terrain.type == TerrainType::Iron)
            {
                // 砖块需要根据block_bit渲染
                uint16_t bit = 0x8000;
                for (int i = 0; i < 16; i++)
                {
                    if (terrain.block_bit & bit)
                    {
                        int offset_x = (i % 4) * MAP_BLOCK_PIECE_SIZE;
                        int offset_y = (i / 4) * MAP_BLOCK_PIECE_SIZE;
                        SDL_Rect srcRect = {offset_x, offset_y, MAP_BLOCK_PIECE_SIZE, MAP_BLOCK_PIECE_SIZE};
                        SDL_Rect dstRect = {x * MAP_BLOCK_WIDTH + offset_x, y * MAP_BLOCK_HEIGHT + offset_y, MAP_BLOCK_PIECE_SIZE, MAP_BLOCK_PIECE_SIZE};
                        SDL_RenderCopy(Game::GetInstance().GetRenderer(), texture, &srcRect, &dstRect);
                    }
                    bit >>= 1;
                }
            }
            else
            {
                SDL_Rect dstRect = {x * MAP_BLOCK_WIDTH, y * MAP_BLOCK_HEIGHT, MAP_BLOCK_WIDTH, MAP_BLOCK_HEIGHT};
                SDL_RenderCopy(Game::GetInstance().GetRenderer(), texture, nullptr, &dstRect);
            }
        }
    }
}

void GameScene::renderBullet()
{
    for(auto& bullet : bullets_)
    {
        bullet->Render();
    }

}

void GameScene::renderTanks()
{
    for(auto& tank : tanks_)
    {
        tank->Render();
    }
}

void GameScene::renderAimetions()
{
    auto renderer = Game::GetInstance().GetRenderer();
    for(auto& animation :animations_)
    {
        animation->Render(renderer);
    }
}

void GameScene::generateEnemy()
{
    index_++;
    if(index_ == 3)
    {
        index_ = 0;
    }
    SDL_Point pos{6*index_*MAP_BLOCK_WIDTH,0};
    auto animation = std::make_shared<BirthAnimetion>(SDL_Point{pos.x,pos.y});
    animation->SetFinishCallback([this,pos]() {
        tanks_.emplace_back(new Enemy(pos.x,pos.y,EnemyType::Power,this));
    });
    animations_.push_back(animation);
}

void GameScene::generatePlayer()
{
    auto animation = std::make_shared<BirthAnimetion>(SDL_Point{4*MAP_BLOCK_WIDTH,12*MAP_BLOCK_HEIGHT});
    animation->SetFinishCallback([this]() {
        player_.reset(new Player(this));
        tanks_.push_back(player_);
    });
    animations_.push_back(animation);
}

Terrain *GameScene::GetTerrain(int x, int y)
{
    if(x<0 || x>=game_.GetWindowWidth() || y<0 || y>=game_.GetWindowHeight())
    {
        return nullptr;
    }
    return &terrainMap_[x / MAP_BLOCK_WIDTH][y / MAP_BLOCK_HEIGHT];
}